<template>
  <!-- 1、用户在组件外部点击, 取消编辑状态 -->
  <!-- 基本思路:（1）阻止click事件冒泡;(2) 在mounted()方法里给body或document绑定click事件;(3) 取消edit状态 -->
  <div ref="propertyGridDiv" class="property-grid" @click.stop>
    <!-- @row-click="handleRowClick" -->
    <!-- @cell-mouse-enter="onCellMoueEnter" -->
    <!-- @current-change="onCurrentChange" -->
    <!-- @cell-mouse-leave="onCellMouseLeave" -->
    <d2-crud
      ref="d2Crud"
      :columns="columns"
      :data="tableData"
      :options="options"
      @cell-data-change="onCellDataChange"
      @cell-click="onCellClick"
      @header-click="onHeaderClick"
      @header-contextmenu="onHeaderContextMenu"
    />
  </div>
</template>

<script>
import PropertyData from './data'
// import resize from './mixins/resize'
import Field from './field'
import d2Crud from '@/components/d2Crud'
import { throttle as _throttle } from 'lodash'

function ToString(type, val) {
  if (typeof val === 'string') return val
  if (val === null || val === undefined) return ''

  // const type = typeof val
  if (type === Field.STRING) {
    return val
  } else if (type === Field.COLOR) {
    return val
  } else if (type === Field.BOOLEAN) {
    return val ? '1' : '0'
  } else {
    return JSON.stringify(val)
  }
}

function FromString(type, val) {
  if (type === Field.STRING) {
    return val
  } else if (type === Field.COLOR) {
    return val
  } else if (type === Field.BOOLEAN) {
    return parseInt(val) === 1
  } else {
    return JSON.parse(val)
  }
}

// 使用d2-crud组件实现的属性网格控件
export default {
  name: 'PropertyGrid',
  components: {
    d2Crud
  },
  // mixins: [resize],
  props: {
    myId: {
      type: String,
      required: true
    },
    datas: {
      type: Array,
      required: true,
      default: () => []
    }
  },
  data() {
    const that = this
    return {
      // d2-crud表格的列定义
      columns: [
        {
          title: '参数',
          key: 'field',
          width: '80',
          // align: 'center',
          // headerAlign: 'center',
          formatter: that.formatField,
          className: 'col-field',
          labelClassName: 'row-header',
          showOverflowTooltip: false
        },
        {
          title: '值',
          key: 'value',
          // align: 'center',
          // headerAlign: 'center',
          formatter: that.formatValue,
          className: 'col-value',
          labelClassName: 'row-header',
          showOverflowTooltip: false,
          // 示例
          // component: {
          //   name: 'el-input',
          //   size: 'small'
          // }
          component: {
            // https://d2admin.fairyever.com/#/demo/d2-crud/demo23
            // 1) 使用自定义render函数
            // render: that.renderFunction,
            // https://d2admin.fairyever.com/#/demo/d2-crud/demo25
            // 2) 或者使用自定义组件(与render函数基本差不多,代码分离后干净一些)
            name: PropertyData,
            // 由于采用d2-crud的这种自定义方式,我们无法给子组件PropertyData传递动态数据
            // 传递一个函数给子组件给调用,来判断是否处于edit状态
            props: {
              isInEdit: that.isInEdit,
              completeEdit: that.completeEdit,
              getObject: that.getObject
            }
          }
        }
      ],
      // d2-crud表格的配置参数
      options: {
        size: 'mini',
        border: true,
        showHeader: false,
        highlightCurrentRow: true,
        emptyText: '暂无数据'
      },
      // 当前点击行
      selectRow: null,
      // 点击的是否value列?
      hitValueColumn: false,
      // 数据映射
      tableDataMap: {},
      // 使用throttle包装,保证click事件只触发一次
      onClickWithThrottle: _throttle(this.onDocumentClick, 100)
    }
  },
  computed: {
    // 计算d2-crud表格需要的数据
    tableData: function() {
      const data = []
      this.datas.forEach(item => {
        data.push({
          field: item.key,
          // value字段统一为string!
          value: ToString(item.type, item.data)
        })
      })
      return data
    }
  },
  watch: {
    datas(val) {
      this.tableDataMap = {}
      val &&
        val.forEach(item => {
          this.tableDataMap[item.key] = item
        })
      this.$emit('completeLoading')
    }
  },
  created() {
    // d2-crud表格自适应高度
    // this.$nextTick(this.autoFitTableHeight)
    this.datas.forEach(item => {
      this.tableDataMap[item.key] = item
    })
    // console.log('property-grid.vue mounted:', this)
  },
  mounted() {
    setTimeout(() => {
      document.addEventListener('click', this.onClickWithThrottle)
    }, 0)
    this.$emit('completeLoading')
  },
  beforeDestroy() {
    window.removeEventListener('click', this.onClickWithThrottle)
  },
  methods: {
    onDocumentClick(event) {
      // console.log('用户在组件外部点击, 取消编辑状态', event)
      // 取消编辑状态
      this.completeEdit()
    },
    // d2-crud表格自适应高度
    autoFitTableHeight() {
      // 设置d2-crud表格的高度
      const el = this.$refs.propertyGridDiv
      // console.log('组件的key:', el)
      const table = el.querySelector('.el-table')
      if (table !== null) {
        // console.log(this.$refs.propertyGridDiv.parentNode)
        const tableHeader = el.querySelector(
          '.el-table > .el-table__header-wrapper'
        )
        const tableBody = el.querySelector(
          '.el-table > .el-table__body-wrapper'
        )
        const childTable = el.querySelector(
          '.el-table > .el-table__body-wrapper > table'
        )
        // 获取当前组件的父容器的高度
        const height = el.clientHeight
        // console.log('组件高度:', height)
        // 更新grid的高度
        table.style.height = height + 'px'
        const bodyHeight = height - tableHeader.clientHeight
        tableBody.style.height = bodyHeight + 'px'
        if (childTable.offsetHeight > bodyHeight) {
          table.classList.add('el-table--scrollable-y')
        } else {
          table.classList.remove('el-table--scrollable-y')
        }
        childTable.style.width = tableBody.clientWidth + 'px'
        // 获取表格数据
        // console.log('表格数据:', this.$refs.d2Crud.d2CrudData)
      }
    },
    // 格式化field列
    formatField(row, column, cellValue, index) {
      // 输出结果: Layer 0 field Layer
      // console.log(row.field, row.value, column.property, cellValue)
      // 此时 row.field === cellValue
      return this.tableDataMap[cellValue].title || cellValue
    },
    // 格式化value列
    // 对于需要更多"显示"效果的, 应使用自定义组件 或 自定义render函数
    formatValue(row, column, cellValue, index) {
      // 输出结果: Layer 0 value 0
      // console.log(row.field, row.value, column.property, cellValue)
      // 此时 row.value === cellValue
      // 获取字段的类型
      // const type = row.value.type
      // 字段数据
      // const data = row.value.data
      // if (type === 1 || type === 2) {
      //   // 浮点数:保留小数点2位
      //   return XEUtils.toFixedString(data, 2)
      // }
      return cellValue
    },
    // 监听单元格数据变化
    onCellDataChange({ rowIndex, key, value, row }) {
      // console.log('响应cell-data-change事件')
      // console.log('字段所在行:', rowIndex)
      // console.log('列名:', key)
      // console.log('值:', value)
      // console.log('行数据:', row)
      console.log('变化: key =', row.field, ' value =', value)
      const type = this.tableDataMap[row.field].type
      // 向父组件发送消息
      this.$emit('change', {
        key: row.field,
        data: FromString(type, value)
      })
    },
    // onCellMouseLeave(row, column, cell, event) {
    //   console.log('鼠标退出单元格, row =', row)
    //   // console.log('单元格点击, column = ', column)
    //   // console.log('单元格点击, cell =', cell)
    //   console.log('鼠标退出单元格, event =', event)
    // },
    // 当某个单元格被点击时会触发该事件
    onCellClick(row, column, cell, event) {
      // console.log('单元格点击, row =', row)
      // console.log('单元格点击, column = ', column)
      // console.log('单元格点击, cell =', cell)
      // console.log('单元格点击, event =', event)
      // 记录当前点击行
      this.selectRow = row
      // 通过colum的class样式来判断点击了哪一列!!!
      this.hitValueColumn = column.className === 'col-value'
      // 3、用户在同一页面的另外一个propertygrid中点击, 取消编辑状态
      //    通过向父组件发送customCellClick事件
      this.$emit('clickBlur', this.myId)
    },
    onHeaderClick(column, event) {
      this.hitValueColumn = false
      // 3、用户在同一页面的另外一个propertygrid中点击, 取消编辑状态
      //    通过向父组件发送customCellClick事件
      this.$emit('clickBlur', this.myId)
    },
    onHeaderContextMenu(column, event) {
      this.hitValueColumn = false
      // 3、用户在同一页面的另外一个propertygrid中点击, 取消编辑状态
      //    通过向父组件发送customCellClick事件
      this.$emit('clickBlur', this.myId)
    },
    isInEdit(scope) {
      // 2、用户在组件内部单元格点击, 点击第2列触发编辑状态, 其它列则取消编辑状态
      return this.selectRow === scope.row && this.hitValueColumn
    },
    completeEdit() {
      this.selectRow = null
      this.hitValueColumn = false
    },
    getObject(key) {
      return this.tableDataMap[key] || null
    }

    // mixins/resize.js
    // onResize () {
    //   console.log('property-grid.vue 自适应...')
    //   // d2-crud表格自适应高度
    //   this.$nextTick(this.autoFitTableHeight)
    // }
  }
}
</script>

<style lang="scss">
@import '../../style/variable.scss';

$cell-font-color: #606266;
$cell-bg-color1: rgba(231, 236, 245, 0.3);
$cell-bg-color2: rgba(231, 236, 245, 0.1);
$cell-bg-color3: rgb(141, 155, 189);

// $font-color:black;
.property-grid {
  height: 100%;
  // 参考: https://www.jb51.net/css/679689.html
  // flex的高度被子元素撑开的问题
  // height: 0;
  // 或者
  // overflow: hidden;
  .d2-crud-body {
    padding: 0 0 !important;
  }
  // 列样式
  .el-table .col-field,
  .el-table .col-value {
    height: $item-height;
    line-height: $item-height;
    padding: 1px 0;
    .cell {
      box-sizing: border-box;
      line-height: $item-height;
      font-size: $item-font-size;
      padding-left: 0;
      padding-right: 0;
      // 嵌入form样式!!!
      @import '../../style/cell-form.scss';
      .no-edit-text {
        padding-left: 5px !important;
      }
    }
  }
  // field列的背景色
  .el-table .col-field {
    background-color: $cell-bg-color1;
    color: $cell-font-color;
    text-align: center;
  }
  // value列的背景色
  .el-table .col-value {
    background-color: $cell-bg-color1;
    color: $cell-font-color;
    text-align: left;
  }

  // 表头样式
  .el-table .col-field.row-header,
  .el-table .col-value.row-header {
    background-color: $cell-bg-color2;
    color: $cell-font-color;
    text-align: center;
    .cell {
      line-height: $item-height;
      color: $cell-font-color;
    }
  }

  .el-table__empty-text {
    line-height: 150px;
  }
}
</style>
